import os
import ujson as json
from random import randint
from subprocess import Popen

from django.conf import settings
from django.db import transaction
from django.db.models import Q

from base import errors
from base import controllers as base_ctl
from account.models import UserModel
from account.models import ScriptModel
from account.models import SettingModel
from workflow.models import WorkModel
from workflow.models import WorkerModel
from account.controllers import user as user_ctl
from utils import time_utils


@transaction.atomic
def create_work(name, host_id, typ, mode, line, script_id, json_id, injure_stop, soul_stop, auto_restart, auto_login, skip_update, auto_change_line, users, extra):
    '''
    创建工作
    '''
    if not WorkModel.check_choices('typ', typ):
        raise errors.CommonError('类型值不正确')
    if not WorkModel.check_choices('mode', mode):
        raise errors.CommonError('模式值不正确')
    if not users:
        raise errors.CommonError('必须选择角色')

    if line == 0:
        line = randint(0, 10)
    data = {
        'name': name,
        'host_id': host_id,
        'line': line,
        'typ': typ,
        'mode': mode,
        'script_id': script_id,
        'json_id': json_id,
        'injure_stop': injure_stop,
        'soul_stop': soul_stop,
        'auto_restart': auto_restart,
        'auto_login': auto_login,
        'skip_update': skip_update,
        'auto_change_line': auto_change_line,
        'extra': extra,
    }
    work_obj = base_ctl.create_obj(WorkModel, data)
    data_list = []
    user_ids = [d.get('id') for d in users]
    for user in users:
        if WorkerModel.objects.filter(user_id=user.get('id')).exists():
            raise errors.CommonError('角色{}已经有工作了，再分配之前请解除原来的工作'.format(user.get('name')))
        data = {
            'user_id': user.get('id'),
            'work_id': work_obj.id,
        }
        data_list.append(data)
    base_ctl.create_objs(WorkerModel, data_list)
    UserModel.objects.filter(id__in=user_ids).update(status=UserModel.ST_WORK)


@transaction.atomic
def update_work(obj_id, name, host_id, typ, mode, line, script_id, json_id, injure_stop, soul_stop, auto_restart, auto_login, skip_update, auto_change_line, extra):
    '''
    编辑工作
    '''
    obj = base_ctl.get_obj(WorkModel, obj_id)
    data = {
        'name': name,
        'host_id': host_id,
        'typ': typ,
        'mode': mode,
        'line': line,
        'script_id': script_id,
        'json_id': json_id,
        'injure_stop': injure_stop,
        'soul_stop': soul_stop,
        'auto_restart': auto_restart,
        'auto_login': auto_login,
        'skip_update': skip_update,
        'auto_change_line': auto_change_line,
        'extra': extra,
    }
    base_ctl.update_obj(WorkModel, obj_id, data)


@transaction.atomic
def delete_work(obj_id):
    '''
    删除工作
    '''
    WorkModel.objects.filter(id=obj_id).delete()


@transaction.atomic
def delete_worker(work_id, user_id):
    '''
    删除工人
    '''
    query = {
        'work_id': work_id,
        'user_id': user_id,
    }
    WorkerModel.objects.filter(**query).delete()
    data = {
        'status': UserModel.ST_ENABLE,
    }
    base_ctl.update_obj(UserModel, user_id, data)


def get_works(typ=None, mode=None, keyword=None, page_num=None, page_size=None):
    '''
    获取工作列表
    '''
    base_query = WorkModel.objects
    if keyword:
        base_query = base_query.filter(name__icontains=keyword)
    if typ:
        base_query = base_query.filter(typ=typ)
    if mode:
        base_query = base_query.filter(mode=mode)

    total = base_query.count()
    objs = base_ctl.query_objs_by_page(base_query, page_num, page_size)
    data_list = []
    for obj in objs:
        data = obj.to_dict()
        data_list.append(data)
    data = {
        'total': total,
        'data_list': data_list,
    }
    return data


def get_work(obj_id):
    '''
    获取工作详情
    '''
    obj = base_ctl.get_obj(WorkModel, obj_id)
    data = obj.to_dict()
    # workers = WorkerModel.objects.filter(work_id=obj.id).all()
    # user_list = []
    # for worker in workers:
    #     user = worker.user.to_dict()
    #     user_list.append(user)
    # data['user_list'] = user_list
    return data


def get_work_base_info(obj_id):
    '''
    获取工作信息
    '''
    obj = base_ctl.get_obj(WorkModel, obj_id)
    workers = WorkerModel.objects.filter(work_id=obj.id).all()
    user_list = []
    for worker in workers:
        user = worker.user.to_dict()
        user_list.append(user)
    data = {
        'data_list': base_ctl.get_obj_base_info(obj),
        'user_list': user_list,
    }
    return data


def get_workers(obj_id):
    '''
    获取工作下工人
    '''
    workers = WorkerModel.objects.filter(work_id=obj_id).all()
    user_list = []
    for worker in workers:
        user = worker.user.to_dict()
        user_list.append(user)
    data = {
        'total': len(user_list),
        'data_list': user_list,
    }
    return data


def run_work(obj_id):
    '''
    运行工作
    '''
    obj = base_ctl.get_obj(WorkModel, obj_id)
    user_ids = []
    if obj.typ in (WorkModel.TYP_LEVELING, WorkModel.TYP_GATHER, WorkModel.TYP_CLOTH):
        user_ids = WorkerModel.objects.filter(work_id=obj.id).values_list('user_id', flat=True).all()
        user_ids = list(set(user_ids))
    elif obj.typ in (WorkModel.TYP_RECEIVE, WorkModel.TYP_SEND):
        user_obj = WorkerModel.objects.filter(work_id=obj.id).first().user
        action = '收' if obj.typ == WorkModel.TYP_RECEIVE else '发'
        user = user_ctl.get_next_user(user_obj.name, obj.extra, action)
        if not user:
            user_ids = [user_obj.id]
        else:
            user_ids = [user.get('id')]

    tmp = 'CGAssistant.exe --gametype={zone} --loginuser={master_id} --loginpwd={password} --gid={slave_id} --server={line} --character={site}'
    if obj.injure_stop:
        tmp += ' --injuryprotect'
    if obj.soul_stop:
        tmp += ' --soulprotect'
    if obj.auto_login is True:
        tmp += ' --autologin'
    if obj.auto_restart is True:
        tmp += ' --scriptautorestart'
    if obj.skip_update is True:
        tmp += ' --skipupdate'
    if obj.auto_change_line is True:
        tmp += ' --autochangeserver'
    if obj.script_id:
        script_obj = ScriptModel.objects.filter(id=obj.script_id).first()
        if script_obj:
            tmp += ' --loadscript={}'.format(script_obj.path)
    if obj.json_id:
        json_obj = SettingModel.objects.filter(id=obj.json_id).first()
        if json_obj:
            tmp += ' --loadsettings={}'.format(json_obj.path)
    users = UserModel.objects.filter(id__in=user_ids).all()
    for user in users:
        server = obj.line
        cmd = tmp.format(zone=user.zone, master_id=user.master_id, password=user.password, slave_id=user.slave_id, line=server, site=user.site)
        os.chdir(settings.CGA_DIR)
        p = Popen(cmd)
        user.cga_pid = p.pid
        data = {'cga_pid': p.pid}
        base_ctl.update_obj(UserModel, user.id, data)